package com.compression.tool.model.task;

import com.compression.tool.compression.CompressionStrategy;
import com.compression.tool.model.enums.TaskStatus;
import com.compression.tool.model.enums.TaskType;
import com.compression.tool.util.FileUtils;

import java.io.File;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
 * @author 自然醒
 * @version 1.0
 */

/**
 * 封装任务信息、状态管理和进度跟踪
 */
public class CompressionTask {
    // 添加日志记录
    private static final Logger logger = Logger.getLogger(CompressionTask.class.getName());
    // 一个用于同步的对象
    private final Object pauseLock = new Object();

    public Object getPauseLock() {
        return pauseLock;
    }

    private final String taskId; // 任务ID
    private final TaskType taskType; // 任务类型
    private final List<File> sourceFiles; // 源文件列表
    private final File targetFile; // 目标文件
    private final CompressionStrategy strategy; // 压缩策略
    private final int compressionLevel; // 压缩级别

    private TaskStatus status; // 任务状态
    private long totalBytes; // 总字节数
    //使用 CAS（Compare-And-Swap）操作，避免了重量级的锁机制
    //原子操作的long 值，可以在多线程环境下安全地进行读写操作
    //AtomicLong 适用于简单的原子操作
    private AtomicLong processedBytes; // 已处理的字节数
    private String errorMessage; // 错误信息
    private long startTime; // 任务开始时间
    private long endTime; // 任务结束时间
    private ProgressListener progressListener; // 进度监听器
    private final AtomicBoolean cancelled = new AtomicBoolean(false); // 任务取消标志
    private Thread exectutionThread; // 执行任务的线程
    private volatile boolean shouldCleanUp = true;


    public CompressionTask(String taskId, TaskType taskType, List<File> sourceFiles,
                           File targetFile, CompressionStrategy strategy, int compressionLevel) {
        this.taskId = taskId;
        this.taskType = taskType;
        this.sourceFiles = sourceFiles;
        this.targetFile = targetFile;
        this.strategy = strategy;
        this.compressionLevel = compressionLevel;

        this.status = TaskStatus.WAITING;
        this.processedBytes = new AtomicLong(0);
        this.totalBytes = FileUtils.calculateFileTotalSize(sourceFiles);

        this.lastLoggedPercent = -1;

        // 记录任务创建信息
        logger.info("创建新任务: " + taskId);
        if (logger.isLoggable(Level.FINE)) {
            logger.fine("任务详情: " + getDetailedTaskInfo());
        }
    }


    //执行任务
    public boolean execute() {
        if (status != TaskStatus.WAITING) {
            throw new IllegalArgumentException("任务已开始或已结束");
        }
        this.exectutionThread = Thread.currentThread();
        if (isCancelled()) {
            logger.info("任务在执行前已被取消");
            setStatus(TaskStatus.CANCELED);
            return false;
        }
        logger.info("开始执行任务: " + taskId + ", 类型: " + taskType);

        // 记录任务描述
        getTaskDescription(); // 这会自动记录任务描述
        setStatus(TaskStatus.RUNNING);
        startTime = System.currentTimeMillis();
        exectutionThread = Thread.currentThread();
        try {
            boolean success;
            switch (taskType) {
                case COMPRESS:
                    logger.info("执行压缩操作");
                    success = compressWithCancellation();
                    break;
                case DECOMPRESS:
                    logger.info("执行解压操作");
                    success = decompressWithCancellation();
                    break;
                case BATCH_COMPRESS:
                    logger.info("执行批量压缩操作");
                    success = executeBatchCompressWithCancellation();
                    break;
                case BATCH_DECOMPRESS:
                    logger.info("执行批量解压操作");
                    success = executeBatchDecompressWithCancellation();
                    break;
                default:
                    success = false;
            }
            //检测任务是否被取消
            if (isCancelled()) {
                setStatus(TaskStatus.CANCELED);
                return false;
            }
            // 记录完成信息
            logger.info("任务完成: " + success);

            complete(success, success ? "任务完成" : "任务失败");
            return success;
        } catch (Exception e) {
            logger.severe("任务执行异常: " + e.getMessage());
            endTime = System.currentTimeMillis();
            setStatus(TaskStatus.CANCELED);
            errorMessage = e.getMessage();
            if (progressListener != null) {
                progressListener.onTaskComplete(false, "错误: " + e.getMessage());
            }

            return false;
        }
    }

    public void complete(boolean success, String message) {
        this.endTime = System.currentTimeMillis();
        this.status = success ? TaskStatus.COMPLETED : TaskStatus.FAILED;
        this.errorMessage = success ? null : message;
        if (progressListener != null) {
            progressListener.onTaskComplete(success, message);
            progressListener.onStatusChange(status);
        }
        logger.info(String.format("任务 %s: %s (%s)",
                taskId, success ? "完成" : "失败", message));
    }

    //能够取消的压缩任务
    private boolean compressWithCancellation() throws InterruptedException {
        return strategy.compress(sourceFiles, targetFile, compressionLevel, this);
    }

    //支持取消的解压
    private boolean decompressWithCancellation() throws InterruptedException {
        if (!FileUtils.isValidArchive(sourceFiles.get(0))) {
            return false;
        }
        return strategy.decompress(sourceFiles.get(0), targetFile, this);
    }

    //批量压缩
    private boolean executeBatchCompressWithCancellation() throws InterruptedException {
        //压缩前先检查是否取消
        if (isCancelled()) {
            throw new InterruptedException("任务已取消");
        }
        for (int i = 0; i < sourceFiles.size(); i++) {
            File sourceFile = sourceFiles.get(i);
            File outputFile = new File(targetFile.getParentFile(), sourceFile.getName() + "." + strategy.getFormatName());
            if (!strategy.compress(List.of(sourceFile), outputFile, compressionLevel, this)) {
                return false;
            }
            updateProgress(sourceFile.length());
        }
        return true;
    }

    //批量解压
    private boolean executeBatchDecompressWithCancellation() throws InterruptedException {
        //解压前先检查是否取消
        if (isCancelled()) {
            throw new InterruptedException("任务已取消");
        }
        for (File sourceFile : sourceFiles) {
            if (FileUtils.isValidArchive(sourceFile) && !strategy.decompress(sourceFile, targetFile, this)) {
                return false;
            }
            updateProgress(sourceFile.length());
        }
        return true;
    }


    //设置任务状态
    public void setStatus(TaskStatus newStatus) {
        this.status = newStatus;
        if (progressListener != null) {
            progressListener.onStatusChange(newStatus);
        }
    }

    // 添加获取详细任务信息的方法
    private String getDetailedTaskInfo() {
        StringBuilder info = new StringBuilder();
        info.append("任务ID: ").append(taskId).append(", ");
        info.append("类型: ").append(taskType).append(", ");
        info.append("源文件: [");

        for (int i = 0; i < Math.min(sourceFiles.size(), 3); i++) {
            if (i > 0) info.append(", ");
            info.append(sourceFiles.get(i).getName());
        }

        if (sourceFiles.size() > 3) {
            info.append(", ... (共").append(sourceFiles.size()).append("个文件)");
        }

        info.append("], 目标: ").append(targetFile.getAbsolutePath());
        info.append(", 压缩级别: ").append(compressionLevel);
        info.append(", 总大小: ").append(FileUtils.formatFileSize(totalBytes));

        return info.toString();
    }

    //获取任务的信息描述
    public String getTaskDescription() {
        String description;
        switch (taskType) {
            case COMPRESS:
                description = String.format("压缩: %s -> %s",
                        getFileListDescription(), targetFile.getName());
                break;
            case DECOMPRESS:
                description = String.format("解压: %s -> %s",
                        sourceFiles.get(0).getName(), targetFile.getName());
                break;
            case BATCH_COMPRESS:
                description = String.format("批量压缩: %d 个文件", sourceFiles.size());
                break;
            case BATCH_DECOMPRESS:
                description = String.format("批量解压: %d 个文件", sourceFiles.size());
                break;
            default:
                description = "未知任务";
        }

        // 添加日志信息 - 记录任务描述
        logger.info("任务描述: " + description);

        // 添加更详细的任务信息到调试日志
        if (logger.isLoggable(Level.INFO)) {
            logger.info("任务详细信息: " + getDetailedTaskInfo());
        }

        return description;
    }

    //获取文件列表的描述
    private String getFileListDescription() {
        if (sourceFiles.size() == 1) {
            return sourceFiles.get(0).getName();
        } else {
            return sourceFiles.size() + " 个文件";
        }
    }

    // 更新进度
    public void updateProgress(long bytesProcessed) {
        long current = processedBytes.addAndGet(bytesProcessed);
        double progress = totalBytes > 0 ? (double) current / totalBytes * 100 : 0;

        // 添加日志信息 - 记录进度更新
        if (logger.isLoggable(Level.FINE)) {
            logger.fine(String.format("任务 %s 进度更新: %.1f%%, 已处理: %s / %s",
                    taskId,
                    progress,
                    FileUtils.formatFileSize(current),
                    FileUtils.formatFileSize(totalBytes)));
        }

        // 每10%记录一次INFO级别的日志，避免日志过多
        int currentPercent = (int) progress / 10 * 10;
        if (currentPercent != lastLoggedPercent && (currentPercent % 10 == 0 || progress >= 100)) {
            logger.info(String.format("任务 %s 进度: %d%%, 已处理: %s / %s",
                    taskId,
                    currentPercent,
                    FileUtils.formatFileSize(current),
                    FileUtils.formatFileSize(totalBytes)));
            lastLoggedPercent = currentPercent;
        }

        if (progressListener != null) {
            progressListener.onProgressUpdate(Math.min(progress, 100));
        }
    }

    // 添加实例变量来跟踪上次记录的百分比
    private int lastLoggedPercent = -1;


    //取消任务
    public void cancel() {
        // 任务已开始或已暂停
        if (status == TaskStatus.RUNNING || status == TaskStatus.PAUSED) {
            //随后我们可以进行任务的取消
            cancelled.set(true);
            setStatus(TaskStatus.CANCELED);
            //中断进程
            if (exectutionThread != null && exectutionThread.isAlive()) {
                exectutionThread.interrupt();
            }
            //执行清理操作(防止后台中还存在线程 导致ui阻塞)
            new Thread(this::performCleanup).start();

        }
    }

    //清理操作
    private void performCleanup() {
        try {
            //删除部分完成的操作
            if (shouldCleanUp && targetFile != null && targetFile.exists()) {
                if (targetFile.isDirectory()) {
                    //如果是目录 则需要删除目录的内容(对于解压的操作) 递归删除
                    deleteDirectoryContent(targetFile);
                } else {
                    //如果是文件 则直接删除(对于压缩的操作)
                    if (targetFile.delete()) {
                        System.out.println("已删除部分完成的文件:" + targetFile.getName());
                    }
                }
            }
            //删除完成后 通知UI清理完成
            if (progressListener != null) {
                progressListener.onTaskComplete(false, "任务取消并完成清理");
            }
        } catch (Exception e) {
            System.err.println("清理操作失败: " + e.getMessage());
        }
    }

    //递归删除目录内容
    private void deleteDirectoryContent(File targetDirectory) {
        File[] files = targetDirectory.listFiles();
        if (files != null) {
            for (File file : files) {
                if (file.isDirectory()) {
                    deleteDirectoryContent(file);
                } else {
                    file.delete();
                }
            }
        }
    }

    //清理操作的状态 因为存在某些地方不需要进行清理
    public void disableCleanup() {
        this.shouldCleanUp = false;
    }

    //设置线程的引用
    public void setExecutionThread(Thread thread) {
        this.exectutionThread = thread;
    }

    //检查取消的状态
    public boolean isCancelled() {
        return cancelled.get();
    }

    //暂停任务
    public void pause() {
        if (status == TaskStatus.RUNNING) {
            setStatus(TaskStatus.PAUSED);
        }
    }

    //恢复任务
    public void resume() {
        synchronized (pauseLock) {
            if (status == TaskStatus.PAUSED) {
                setStatus(TaskStatus.RUNNING);
                pauseLock.notifyAll();
            }
        }
    }


    // Getter 方法
    public String getTaskId() {
        return taskId;
    }

    public TaskType getTaskType() {
        return taskType;
    }

    public List<File> getSourceFiles() {
        return sourceFiles;
    }

    public File getTargetFile() {
        return targetFile;
    }

    public TaskStatus getStatus() {
        return status;
    }

    // 计算进度
    public double getProgress() {
        return totalBytes > 0 ? (double) processedBytes.get() / totalBytes * 100 : 0;
    }

    public long getTotalBytes() {
        return totalBytes;
    }

    public long getProcessedBytes() {
        return processedBytes.get();
    }

    public String getErrorMessage() {
        return errorMessage;
    }

    // 计算已用时间
    public long getElapsedTime() {
        return (status == TaskStatus.RUNNING ? System.currentTimeMillis() : endTime) - startTime;
    }

    // 计算剩余时间
    public long getEstimatedRemainingTime() {
        if (getProgress() == 0 || status != TaskStatus.RUNNING) return 0;
        long elapsed = getElapsedTime();
        return (long) (elapsed / getProgress() * (100 - getProgress()));
    }

    // 设置进度监听器
    public void setProgressListener(ProgressListener listener) {
        this.progressListener = listener;
    }

    public ProgressListener getProgressListener() {
        return progressListener;
    }


    @Override
    public String toString() {
        return String.format("CompressionTask{id=%s, type=%s, status=%s, progress=%.1f%%}",
                taskId, taskType, status, getProgress());
    }


    //下面方法已抽取出来当作文件的基本操作 FileUtils

    // 添加文件大小格式化方法（如果还没有）
    /**
     private String formatFileSize(long size) {
     if (size < 1024) {
     return size + " B";
     } else if (size < 1024 * 1024) {
     return String.format("%.1f KB", size / 1024.0);
     } else if (size < 1024 * 1024 * 1024) {
     return String.format("%.1f MB", size / (1024.0 * 1024.0));
     } else {
     return String.format("%.1f GB", size / (1024.0 * 1024.0 * 1024.0));
     }
     }
     */

    /**
     //     * 计算所有文件大小
     //     *
     //     * @param files
     //     * @return
     //     */
//    private long calculateTotalSize(List<File> files) {
//        long total = 0;
//        for (File file : files) {
//            total += calculateFileSize(file.toPath());
//        }
//        return total;
//    }
//
//    /**
//     * 使用nio计算文件大小
//     *
//     * @param path
//     * @return
//     */
//    private long calculateFileSize(Path path) {
//        try {
//            if (Files.isRegularFile(path)) {
//                return Files.size(path);
//            } else if (Files.isDirectory(path)) {
//                // 使用try-with-resources确保资源释放
//                try (Stream<Path> walk = Files.walk(path)) {
//                    // 对于非常大的目录结构，可能消耗较多内存
//                    return walk
//                            .filter(Files::isRegularFile)// 返回Stream<Path>，需要处理大量文件时可能内存压力较大
//                            .mapToLong(p -> {
//                                try {
//                                    return Files.size(p);
//                                } catch (IOException e) {
//                                    return 0L;
//                                }
//                            })
//                            .sum();
//                }
//            }
//        } catch (IOException e) {
//            System.err.println("无法访问: " + path);
//        } catch (SecurityException e) {
//            System.err.println("权限不足: " + path);
//        }
//        return 0;
//    }


//    /**
//     * 计算所有文件大小
//     *
//     * @param files
//     * @return
//     */
//    private long calculateTotalSize(List<File> files) {
//        long total = 0;
//        for (File file : files) {
//            total += calculateFileSize(file);
//        }
//        return total;
//    }
//
//    /**
//     * 递归计算文件大小
//     * 但是性能可能不太好 在大量文件的情况下会比较慢
//     * @param file
//     * @return
//     */
//    private long calculateFileSize(File file) {
//        if (file.isFile()) {
//            return file.length();
//        } else if (file.isDirectory()) {
//            File[] files = file.listFiles();
//            if (files != null) {
//                long total = 0;
//                for (File f : files) {
//                    total += calculateFileSize(f);
//                }
//                return total;
//            }
//        }
//        // 文件不存在
//        return 0;
//    }
}
